package ru.timofeyco.justfeelbetter;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.StreamCorruptedException;
import java.util.Calendar;
import java.util.Date;

import ru.timofeyco.justfeelbetter.db.JustFeelBetterDatabase;
import ru.timofeyco.justfeelbetter.model.DayResult;
import ru.timofeyco.justfeelbetter.model.Drill;
import ru.timofeyco.justfeelbetter.model.DrillType;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity;
import android.widget.Toast;

public class PreferencesActivity extends PreferenceActivity {
	JustFeelBetterDatabase dbHelper;
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		addPreferencesFromResource(R.xml.preferences);
		
		dbHelper = new JustFeelBetterDatabase(this);
		
		Preference cleanDayPreference = findPreference("clean_day_pref");
		cleanDayPreference.setOnPreferenceClickListener(onCleanDayClickListener);
		
		Preference cleanAllPreference = findPreference("clean_all_pref");
		cleanAllPreference.setOnPreferenceClickListener(onCleanAllClickListener);
		
		Preference exportPreference = findPreference("export_data_pref");
		exportPreference.setOnPreferenceClickListener(onExportClickListener);
		
		Preference importPreference = findPreference("import_data_pref");
		importPreference.setOnPreferenceClickListener(onImportClickListener);
		
		Preference drillTypesPreference = findPreference("drill_types_pref");
		drillTypesPreference.setOnPreferenceClickListener(onDrillTypesClickListener);
	}
	
	private void resetDayResult() throws IOException {
		Date today = Calendar.getInstance().getTime();
		today = new Date(today.getYear(), today.getMonth(), today.getDate());
		
		DayResult dayResult = dbHelper.getDayResult(today);
		if (dayResult == null) {
			dayResult = new DayResult(today, 0);
			dbHelper.insertDayResult(dayResult);
		}
	}
	
	private OnPreferenceClickListener onCleanDayClickListener = new OnPreferenceClickListener() {
		@Override
		public boolean onPreferenceClick(Preference preference) {
			AlertDialog.Builder builder = new AlertDialog.Builder(PreferencesActivity.this);
			builder.setMessage(getString(R.string.clear_day_dialog))
					.setCancelable(false)
					.setPositiveButton(getString(R.string.yes), new DialogInterface.OnClickListener() {
						public void onClick(DialogInterface dialog, int which) {
							dbHelper.deleteDrillsByDay(Calendar.getInstance().getTime());
							try {
								resetDayResult();
							} catch (IOException e) {
								// TODO: handle exception
								e.printStackTrace();
							}
							Toast.makeText(PreferencesActivity.this, getString(R.string.day_cleaned_msg), Toast.LENGTH_LONG).show();
						}
					})
					.setNegativeButton(getString(R.string.no), new DialogInterface.OnClickListener() {
						public void onClick(DialogInterface dialog, int which) {
							dialog.cancel();							
						}
					});			
			AlertDialog alert = builder.create();
			alert.show();
			return true;
		}
	};
	
	private OnPreferenceClickListener onCleanAllClickListener = new OnPreferenceClickListener() {
		@Override
		public boolean onPreferenceClick(Preference preference) {
			AlertDialog.Builder builder = new AlertDialog.Builder(PreferencesActivity.this);
			builder.setMessage(getString(R.string.clear_all_dialog))
					.setCancelable(false)
					.setPositiveButton(getString(R.string.yes), new DialogInterface.OnClickListener() {
						public void onClick(DialogInterface dialog, int which) {
							dbHelper.deleteAllDrills();
							try {
								resetDayResult();
							} catch (IOException e) {
								// TODO: handle exception
								e.printStackTrace();
							}
							Toast.makeText(PreferencesActivity.this, getString(R.string.all_cleaned_msg), Toast.LENGTH_LONG).show();
						}
					})
					.setNegativeButton(getString(R.string.no), new DialogInterface.OnClickListener() {
						public void onClick(DialogInterface dialog, int which) {
							dialog.cancel();							
						}
					});			
			AlertDialog alert = builder.create();
			alert.show();
			
			return true;
		}
	};
	
	private final static String DRILL_TYPES_FILE_NAME = "drill_types_file";
	private final static String DRILLS_FILE_NAME = "drills_file";
	private final static String DAY_RESULTS_FILE_NAME = "day_results_file";
	
	public static byte[] getBytes(Object obj) throws java.io.IOException{
	      ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
	      ObjectOutputStream oos = new ObjectOutputStream(bos); 
	      oos.writeObject(obj);
	      oos.flush(); 
	      oos.close(); 
	      bos.close();
	      byte [] data = bos.toByteArray();
	      return data;
	}
	
	public static Object getObjectFromBytes(byte[] bytes) throws StreamCorruptedException, IOException, ClassNotFoundException {
		ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
		ObjectInputStream ois = new ObjectInputStream(bis);
		Object outObject = ois.readObject();
		ois.close();
		bis.close();
		return outObject;
	}
	
	private OnPreferenceClickListener onExportClickListener = new OnPreferenceClickListener() {
		@Override
		public boolean onPreferenceClick(Preference preference) {											
			DrillType[] drillTypes = dbHelper.getDrillTypes();
			Drill[] drills = dbHelper.getDrills();
			DayResult[] dayResults = dbHelper.getDayResults();
			
			File appDir = new File(Environment.getExternalStorageDirectory(), "data/ru.timofeyco.justfeelbetter");
			appDir.mkdirs();
			
			exportDrillTypes(drillTypes, appDir);
			exportDrills(drills, appDir);
			exportDayResults(dayResults, appDir);		
			
			Toast.makeText(PreferencesActivity.this, getString(R.string.data_exported_msg), Toast.LENGTH_LONG).show();
			return true;
		}
	};
	
	private OnPreferenceClickListener onImportClickListener = new OnPreferenceClickListener() {
		@Override
		public boolean onPreferenceClick(Preference preference) {
			AlertDialog.Builder builder = new AlertDialog.Builder(PreferencesActivity.this);
			builder.setMessage(getString(R.string.import_dialog))
					.setCancelable(false)
					.setPositiveButton(getString(R.string.yes), new DialogInterface.OnClickListener() {
						public void onClick(DialogInterface dialog, int which) {

							DrillType[] drillTypes = null;
							Drill[] drills = null;
							DayResult[] dayResults = null;
							
							File appDir = new File(Environment.getExternalStorageDirectory(), "data/ru.timofeyco.justfeelbetter");
							
							drillTypes = readDrillType(appDir);
							drills = readDrills(appDir);
							dayResults = readDayResults(appDir);
							
							importDrillTypes(drillTypes);
							importDrills(drills);
							importDayResults(dayResults);		
							
							Toast.makeText(PreferencesActivity.this, getString(R.string.data_imported_msg), Toast.LENGTH_LONG).show();
						}
					})
					.setNegativeButton(getString(R.string.no), new DialogInterface.OnClickListener() {
						public void onClick(DialogInterface dialog, int which) {
							dialog.cancel();							
						}
					});			
			AlertDialog alert = builder.create();
			alert.show();
			return true;
		}
	};
	
	private OnPreferenceClickListener onDrillTypesClickListener = new OnPreferenceClickListener() {
		@Override
		public boolean onPreferenceClick(Preference preference) {
			Intent preferencesIntent =  new Intent(preference.getContext(), TrainingPrefDrillTypes.class);
			PreferencesActivity.this.startActivityForResult(preferencesIntent, RESULT_OK);
			return true;
		}

	};
	
	private void exportDrillTypes(DrillType[] drillTypes, File appDir) {
		try {
			File drillTypesFile = new File(appDir, DRILL_TYPES_FILE_NAME);
			FileOutputStream foutDrillTypes = new FileOutputStream(drillTypesFile);
			foutDrillTypes.write(getBytes(drillTypes));
			foutDrillTypes.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	private void exportDayResults(DayResult[] dayResults, File appDir) {
		try {
			File dayResultFile = new File(appDir, DAY_RESULTS_FILE_NAME);
			FileOutputStream foutDayResults = new FileOutputStream(dayResultFile);
			foutDayResults.write(getBytes(dayResults));
			foutDayResults.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private void exportDrills(Drill[] drills, File appDir) {
		try {
			File drillsFile = new File(appDir, DRILLS_FILE_NAME);
			FileOutputStream foutDrills = new FileOutputStream(drillsFile);
			foutDrills.write(getBytes(drills));
			foutDrills.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
	}
	
	private DrillType[] readDrillType(File appDir) {
		DrillType[] drillTypes = null;
		// read drill types
		try {
			File drillTypesFile = new File(appDir, DRILL_TYPES_FILE_NAME);
			FileInputStream fiDrillTypes = new FileInputStream(drillTypesFile);
			byte[] bytes = new byte[fiDrillTypes.available()];
			fiDrillTypes.read(bytes);
			drillTypes = (DrillType[])getObjectFromBytes(bytes);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return drillTypes;
	}
	
	protected Drill[] readDrills(File appDir) {
		Drill[] drills = null;
		// read drills
		try {
			File drillsFile = new File(appDir, DRILLS_FILE_NAME);
			FileInputStream fiDrills = new FileInputStream(drillsFile);
			byte[] bytes = new byte[fiDrills.available()];
			fiDrills.read(bytes);
			drills = (Drill[])getObjectFromBytes(bytes);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return drills;
	}
	
	protected DayResult[] readDayResults(File appDir) {
		DayResult[] dayResults = null;
		try {
			File dayResultsFile = new File(appDir, DAY_RESULTS_FILE_NAME);
			FileInputStream fiDayResults = new FileInputStream(dayResultsFile);				
			byte[] bytes = new byte[fiDayResults.available()];
			fiDayResults.read(bytes);
			dayResults = (DayResult[])getObjectFromBytes(bytes);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return dayResults;
	}

	private void importDrillTypes(DrillType[] drillTypes) {
		for (DrillType drillType : drillTypes) {
			try {
				dbHelper.insertDrillType(drillType);
			} catch(IOException ex) {
				// TODO: handle case when drill type exists
			}
		}
	}
	
	private void importDrills(Drill[] drills) {
		for (Drill drill : drills) {
			try {
				dbHelper.insertDrill(drill);
			} catch (IOException ex) {
				// TODO: handle case when drill exists
			}				
		}		
	}
	
	private void importDayResults(DayResult[] dayResults) {
		for (DayResult dayResult : dayResults) {
			try {
				dbHelper.insertDayResult(dayResult);
			} catch (IOException e) {
				dbHelper.updateDayResult(dayResult);
			}
		}
	}
}
